﻿// Sequin.Sequences.SequenceStatistics
//
// (c) 2011 Arthur Pitman
//
// Part of the Sequin Library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License (Version 2.1) as published by the Free Software Foundation.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License (Version 2.1) along with this library; if not, write to the 
// Free Software Foundation, Inc., 
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
// or see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;

namespace Sequin.Sequences
{
    /// <summary>
    /// Calculates a variety of statistics for a set of sequences
    /// </summary>
    public class SequenceStatistics
    {
        /// <summary>
        /// The number of sequences
        /// </summary>
        public long SequenceCount { get; protected set; }

        /// <summary>
        /// The total number of elements
        /// </summary>
        public long ElementCount { get; protected set; }

        /// <summary>
        /// The total number of items
        /// </summary>
        public long ItemCount { get; protected set; }

        /// <summary>
        /// The average number of elements in a <see cref="Sequence"/>
        /// </summary>
        public double AverageElements { get; protected set; }

        /// <summary>
        /// The average number of items in a <see cref="Sequence"/>
        /// </summary>
        public double AverageItems { get; protected set; }

        /// <summary>
        /// The average number of items in an element
        /// </summary>
        public double AverageItemsPerElement { get; protected set; }


        /// <summary>
        /// The number of distinct items
        /// </summary>
        public long DistinctItemCount { get; protected set; }

        /// <summary>
        /// The longest sequence (number of elements)
        /// </summary>
        public long LongestSequenceElementCount { get; protected set; }

        /// <summary>
        /// The longest sequence (number of items)
        /// </summary>
        public long LongestSequenceItemCount { get; protected set; }

        /// <summary>
        /// The longest element (number of items)
        /// </summary>
        public long LongestElement { get; protected set; }

        /// <summary>
        /// Initializes a new <see cref="SequenceStatistics"/> instance for a set of <see cref="Sequence"/> objects
        /// </summary>
        /// <param name="sequences">The set of <see cref="Sequence"/> objects</param>
        public SequenceStatistics(IEnumerable<Sequence> sequences)
        {
            HashSet<int> uniqueItems = new HashSet<int>();
            foreach (var sequence in sequences)
            {
                int itemsInSequence = 0;
                foreach (var element in sequence.Value)
                {
                    int itemsInElement = 0;
                    foreach (var item in element)
                    {
                        uniqueItems.Add(item);
                        ItemCount++;
                        itemsInElement++;
                        itemsInSequence++;
                    }
                    if (itemsInElement > LongestElement)
                        LongestElement = itemsInElement;
                    ElementCount++;
                }

                if (sequence.Value.Length > LongestSequenceElementCount)
                    LongestSequenceElementCount = sequence.Value.Length;

                if (itemsInSequence > LongestSequenceItemCount)
                    LongestSequenceItemCount = itemsInSequence;

                SequenceCount++;
            }
            DistinctItemCount = uniqueItems.Count;
            AverageElements = (double)(ElementCount) / SequenceCount;
            AverageItems = (double)(ItemCount) / SequenceCount;
            AverageItemsPerElement = (double)(ItemCount) / ElementCount;
        }

        /// <summary>
        /// Converts this <see cref="SequenceStatistics"/> object to a <see cref="string"/>
        /// </summary>
        /// <returns>The resulting <see cref="string"/></returns>
        public override string ToString()
        {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.AppendFormat("Sequence Statistics:\n");
            stringBuilder.AppendFormat("{0} sequences, containing a total of {1} elements and {2} items\n",
                SequenceCount,
                ElementCount,
                ItemCount);
            stringBuilder.AppendFormat("{0} unique items\n",
                DistinctItemCount);
            stringBuilder.AppendFormat("On average, a sequence contains {0:N2} elements and a total of {1:N2} items\n",
                AverageElements,
                AverageItems);
            stringBuilder.AppendFormat("On average, an element contained {0:N2} items\n",
                AverageItemsPerElement);
            stringBuilder.AppendFormat("The maximum sequence length was either {0} elements or {1} items\n",
                LongestSequenceElementCount,
                LongestSequenceItemCount);
            stringBuilder.AppendFormat("The longest element contained {0} items\n",
                LongestElement);
            return stringBuilder.ToString();
        }

    }
}
